//
//  QrCodeManager.swift
//  linjwDemo
//
//  Created by Linjw on 2022/6/14.
//  Copyright © 2022 linjw(10126121@qq.com). All rights reserved.
//

import UIKit
import AVFoundation
import Photos

/**
 使用逻辑
 
 1、生成对象, (可选)配置扫码区域,(可选)配置扫码类型
 2、配置扫码图层 configPreView(_ view: UIView, rect: CGRect = CGRect.zero)
 3、(可选)配置扫码区域,(可选)配置扫码类型
 4、配置扫描结果处理 resultAction
 5、开始扫描 startScan
 6、处理扫描结果

 */
/// 扫码管理
@objcMembers public class JWQRCodeManager: NSObject {
    
    /// 是否正在运行扫码
    public var isRunning: Bool { self.session.isRunning }
    
    /// 扫码结果
    public lazy var resultAction: ((String?)->())? = nil
    
    /// 是否当扫码完成自动停止
    public lazy var isAutoStopWhenFinish: Bool = true
    
    /// MARK - 设备
    private lazy var device: AVCaptureDevice? = AVCaptureDevice.default(for: AVMediaType.video)
    
    /// MARK - 设备输入
    private lazy var input: AVCaptureDeviceInput? = self.device != nil ? try? AVCaptureDeviceInput(device: self.device!) : nil
    
    /// MARK - 输出数据
    private lazy var output: AVCaptureMetadataOutput = AVCaptureMetadataOutput()
    
    /// MARK - 会话
    private lazy var session: AVCaptureSession = {
        let it = AVCaptureSession()
        it.sessionPreset = AVCaptureSession.Preset.high
        return it
    }()
    
    /// MARK - 预览层
    private lazy var previewLayer: AVCaptureVideoPreviewLayer = {
        let it = AVCaptureVideoPreviewLayer(session: session)
        it.videoGravity = AVLayerVideoGravity.resizeAspectFill
        it.backgroundColor = UIColor.black.cgColor
        return it
    }()
    
    /// 当前扫码结果是否处理(意思就是扫码只处理第一次结果，因为扫码可能一直扫，会一直有结果。)
    private var isNeedScanResult: Bool = false
    
    /// 是否打开闪光灯
    public var isOpenTorchlight: Bool {
        set {
            input?.device.torchMode = newValue ? AVCaptureDevice.TorchMode.on : AVCaptureDevice.TorchMode.off
        }
        get {
            return input?.device.torchMode == AVCaptureDevice.TorchMode.on ? true: false
        }
    }
    
    /// MARK - 是否支持闪光灯
    public var hasTorch: Bool { return self.device != nil && self.device!.hasFlash && self.device!.hasTorch }
    
    /// 扫码限制类型
    public var scanCodeTypes: [AVMetadataObject.ObjectType] = [.qr, .code128, .ean8, .ean13] {
        didSet {
            self.output.metadataObjectTypes = scanCodeTypes
        }
    }
    
    override public init() {
        
        super.init()
        
        self.setup()
        
    }
    
    /// 配置预览view
    public func configPreView(_ view: UIView, rect: CGRect = CGRect.zero) {
        
        if self.previewLayer.superlayer != view.layer {
            view.layer.insertSublayer(self.previewLayer, at: 0)
        }
        
        let toRect = rect == .zero ? view.bounds : rect
        
        self.previewLayer.frame = toRect
        
    }
    
    /// 配置预览view.frame
    public func configPreViewFrame(_ toRect: CGRect) {
        self.previewLayer.frame = toRect
    }
    
    /// 初始化
    private func setup() {
        
        guard let input = input else {
            debugPrint("初始化input出错")
            return
        }
        
        /// 配置输入输出
        if self.session.canAddInput(input) { self.session.addInput(input) }
        if self.session.canAddOutput(self.output) { self.session.addOutput(self.output) }
        self.output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
        /// 配置扫码类型
        self.scanCodeTypes = [.qr, .code128, .ean8, .ean13]
        
        if let device = device {
            /// 设置自动对焦
            if device.isFocusPointOfInterestSupported && device.isFocusModeSupported(AVCaptureDevice.FocusMode.continuousAutoFocus) {
                do {
                    try input.device.lockForConfiguration()
                    input.device.focusMode = AVCaptureDevice.FocusMode.continuousAutoFocus
                    input.device.unlockForConfiguration()
                }
                catch let error as NSError {
                    debugPrint("device.lockForConfiguration(): \(error)")
                }
            }
        }
    }
    
    /// 开始扫码
    public func startScan() {
        if !session.isRunning {
            isNeedScanResult = true
            session.startRunning()
        }
    }
    
    /// 结束扫码
    public func stopScan() {
        if session.isRunning {
            isNeedScanResult = false
            session.stopRunning()
        }
    }
    
    /// MARK - 切换识别区域
    /// 区域大小是百分比: Rect(x: x / preView.width, y / preView.height, w / preView.width, h / preView.height)
    public func changeScan(rect: CGRect) {
        
        let isRunning = self.session.isRunning
        if isRunning { stopScan() }
        output.rectOfInterest = rect
        if isRunning {  startScan() }
        
    }
    
    /// MARK - 切换识别码的类型
    public func changeScan(codeType: [AVMetadataObject.ObjectType]) {
        let isRunning = self.session.isRunning
        if isRunning { stopScan() }
        output.metadataObjectTypes = codeType
        if isRunning {  startScan() }
    }
    
    /// MARK - 获取系统默认支持的码的类型
    static public func defaultMetaDataObjectTypes() ->[AVMetadataObject.ObjectType] {
        
        var types = [
            AVMetadataObject.ObjectType.qr,
            AVMetadataObject.ObjectType.upce,
            AVMetadataObject.ObjectType.code39,
            AVMetadataObject.ObjectType.code39Mod43,
            AVMetadataObject.ObjectType.ean13,
            AVMetadataObject.ObjectType.ean8,
            AVMetadataObject.ObjectType.code93,
            AVMetadataObject.ObjectType.code128,
            AVMetadataObject.ObjectType.pdf417,
            AVMetadataObject.ObjectType.aztec,
        ]
        
        types.append(AVMetadataObject.ObjectType.interleaved2of5)
        types.append(AVMetadataObject.ObjectType.itf14)
        types.append(AVMetadataObject.ObjectType.dataMatrix)
        
        types.append(AVMetadataObject.ObjectType.interleaved2of5)
        types.append(AVMetadataObject.ObjectType.itf14)
        types.append(AVMetadataObject.ObjectType.dataMatrix)
        
        return types as [AVMetadataObject.ObjectType]
    }
    
}


extension JWQRCodeManager: AVCaptureMetadataOutputObjectsDelegate {
    
    /// 扫码结果
    public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        
        var result: (type: AVMetadataObject.ObjectType, code: String?, corners: [CGPoint])? = nil
        
        for current: Any in metadataObjects {
            if (current as AnyObject).isKind(of: AVMetadataMachineReadableCodeObject.self) {
                let code = current as! AVMetadataMachineReadableCodeObject
                // 码类型
                let codeType = code.type
                // 码内容
                let codeContent = code.stringValue
                // 4个字典，分别 左上角-右上角-右下角-左下角的 坐标百分百，可以使用这个比例抠出码的图像
                result = (type: codeType, code: codeContent, corners: code.corners)
            }
        }
        
        if let result = result {
            debugPrint("扫码结果[\(result.type.rawValue)]: \(result.code ?? "")")
            if isAutoStopWhenFinish { stopScan() }
            resultAction?(result.code)
        }
        
    }
    
}


/// 授权相关的拓展
extension JWQRCodeManager {
    
    /// 授权相机
    public static func authorizeCamera(comletion: @escaping (Bool) -> Void) {
        
        let granted = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)
        
        switch granted {
        case .authorized:
            comletion(true)
        case .denied:
            comletion(false)
        case .restricted:
            comletion(false)
        default:
            AVCaptureDevice.requestAccess(for: AVMediaType.video, completionHandler: { (granted) in
                DispatchQueue.main.async {
                    comletion(granted)
                }
            })
        }
        
    }
    
    /// MARK - 获取相册权限
    public static func authorizePhoto(comletion: @escaping (Bool) -> Void)
    {
        let granted = PHPhotoLibrary.authorizationStatus()
        switch granted {
        case .authorized:
            comletion(true)
        case .denied, .restricted:
            comletion(false)
        default:
            PHPhotoLibrary.requestAuthorization({ (state) in
                DispatchQueue.main.async {
                    comletion(state == PHAuthorizationStatus.authorized ? true : false)
                }
            })
        }
    }
    
    /// MARK - 跳转到APP系统设置权限界面
    public static func jumpToSystemPrivacySetting()
    {
        guard let appSetting = URL(string: UIApplication.openSettingsURLString) else {
            return
        }
        
        if #available(iOS 10, *) {
            UIApplication.shared.open(appSetting, options: [:], completionHandler: nil)
        } else {
            UIApplication.shared.openURL(appSetting)
        }
    }
    
}
